package au.org.aurin.wif.io; import java.io.IOException; import java.io.OutputStreamWriter; import java.nio.charset.Charset; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.geotools.feature.FeatureCollection; import org.geotools.geojson.feature.FeatureJSON; import org.springframework.http.HttpInputMessage; import org.springframework.http.HttpOutputMessage; import org.springframework.http.MediaType; import org.springframework.http.converter.AbstractHttpMessageConverter; import org.springframework.http.converter.HttpMessageNotReadableException; import org.springframework.http.converter.HttpMessageNotWritableException; /** * Implementation of * {@link org.springframework.http.converter.HttpMessageConverter * HttpMessageConverter} that can read and write GeoJSON using <a * href="http://geotools.org/">Geotools'</a> {@link FeatureJSON}. * * <p> * By default, this converter supports {@code application/geo+json}. This can be * overridden by setting the {@link #setSupportedMediaTypes(List) * supportedMediaTypes} property. * * @author Gerson Galang */ public class FeatureHttpMessageConverter extends AbstractHttpMessageConverter<Object> { /** The logger. */ private static final Log LOGGER = LogFactory .getLog(FeatureHttpMessageConverter.class); public static final Charset DEFAULT_CHARSET = Charset.forName("UTF-8"); private FeatureJSON featureJSON = new FeatureJSON(); public FeatureHttpMessageConverter() { super(new MediaType("application", "geo+json", DEFAULT_CHARSET)); } public void setFeatureJSON(final FeatureJSON featureJSON) { this.featureJSON = featureJSON; } @Override protected Object readInternal(final Class<? extends Object> arg0, final HttpInputMessage inputMessage) throws IOException, HttpMessageNotReadableException { LOGGER.debug("Entering FeatureHttpMessageConverter.readInternal()."); final MediaType contentType = inputMessage.getHeaders().getContentType(); LOGGER.debug("content type of the message received: " + contentType); return featureJSON.readFeatureCollection(inputMessage.getBody()); } @Override protected boolean supports(final Class<?> arg0) { LOGGER.debug("json.FeatureHttpMessageConverter supports(" + arg0.getName() + ")?"); if (FeatureCollection.class.isAssignableFrom(arg0)) { return true; } return false; } @Override protected void writeInternal(final Object o, final HttpOutputMessage outputMessage) throws IOException, HttpMessageNotWritableException { LOGGER.debug("Entering FeatureHttpMessageConverter.writeInternal()."); LOGGER.debug("Content type of the outputMessage " + outputMessage.getHeaders().getContentType()); featureJSON.setEncodeFeatureCollectionBounds(true); featureJSON.setEncodeNullValues(true); // TODO we'll need to enable this once geotools allow us to patch // GML2ParsingUtils class and set SRID on each of the features created // for the call to encodeCRS not to throw an exception, we'll need to check // for the existence of CRS info in the feature collection before we set // this flag... if (((FeatureCollection) o).getBounds().getCoordinateReferenceSystem() != null) { featureJSON.setEncodeFeatureCollectionCRS(true); } featureJSON.writeFeatureCollection((FeatureCollection) o, new OutputStreamWriter(outputMessage.getBody())); } }